home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / Apps / ScreenSavers / BackSpaceViews / MovieShowView.BackModule / MovieShowViewPart.m < prev    next >
Encoding:
Text File  |  1995-06-12  |  11.5 KB  |  515 lines

  1. /*
  2.  * MovieShowView - version 1.0
  3.  *
  4.  * hacked from: "SlideShowView" by brighton@phuket.nbn.com, 13 Nov 91
  5.  * hacked by: Paul Burchard <burchard@math.utah.edu>
  6.  * further hacked by sam <sam_s@next.com> to add BackSpace 3.0 inspector
  7.  */
  8.  
  9. #import <appkit/NXImage.h>        // NXImage
  10. #import <appkit/OpenPanel.h>          // NXRunAlertPanel()
  11. #import <appkit/Text.h>           // NXOrderStrings()
  12. #import <appkit/Button.h>
  13. #import <dpsclient/wraps.h>       // PSsetgray()
  14. #import <defaults/defaults.h>        // NXDefaults stuff
  15. #import <libc.h>                  // lots of sys stuff
  16. #import <math.h>                  // floor()
  17. #import <string.h>                // strcmp(), index()
  18. #import <c.h>                     // TRUE, FALSE, etc
  19. #import <sys/dir.h>               // opendir(), etc
  20.  
  21. #import "MovieShowViewPart.h"
  22. #import "Thinker.h"
  23.  
  24.  
  25. // States.
  26. #define msh_DARK 0
  27. #define msh_BEGIN 1
  28. #define msh_FRAME 2
  29. #define msh_END 3
  30.  
  31.  
  32. static const char *module = "MovieShow";
  33.  
  34.  
  35. static int stringToBool(const char *answer)
  36. {
  37.     if (strcasecmp(answer, "yes") == 0) return 1;
  38.     if (strcasecmp(answer, "on") == 0) return 1;
  39.  
  40.     return atoi(answer); // returns zero if no digits encountered
  41. }
  42.  
  43.  
  44. @implementation MovieShowView
  45.  
  46. + initialize
  47. {
  48.     static NXDefaultsVector MovieShowDefaults = {
  49.         { "Movie", "~/Library/Images/MovieShow.anim" },
  50.         { "FrameTime", "1" },
  51.         { "BeginPause", "12" },
  52.         { "EndPause", "30" },
  53.         { "DarkTime", "0" },
  54.         { "Jump", "YES" },
  55.         { "SlideFrames", "NO" },
  56.         { "SlidePauses", "NO" },
  57.         { "TimeUnit", "25" },
  58.         { NULL }
  59.     };
  60.  
  61.     NXRegisterDefaults(module, MovieShowDefaults);
  62.  
  63.     return self;
  64. }
  65.  
  66. - getDefaults
  67. {
  68.     const char *app = module;
  69.  
  70.  
  71.     // Read from defaults database.
  72.     NXUpdateDefaults();
  73.  
  74.     theMovie = NXGetDefaultValue(app, "Movie");
  75.  
  76.     timeunit = (unsigned)atoi(NXGetDefaultValue(app, "TimeUnit"));
  77.     frametime = (unsigned)atoi(NXGetDefaultValue(app, "FrameTime"));
  78.     beginpause = (unsigned)atoi(NXGetDefaultValue(app, "BeginPause"));
  79.     endpause = (unsigned)atoi(NXGetDefaultValue(app, "EndPause"));
  80.     darktime = (unsigned)atoi(NXGetDefaultValue(app, "DarkTime"));
  81.  
  82.     if(stringToBool(NXGetDefaultValue(app, "SlideFrames"))) slideframes = YES;
  83.     else slideframes = NO;
  84.     if(stringToBool(NXGetDefaultValue(app, "SlidePauses")))
  85.         slidebegin = slideend = YES;
  86.     else slidebegin = slideend = NO;
  87.     if(stringToBool(NXGetDefaultValue(app, "Jump"))) jump = YES;
  88.     else jump = NO;
  89.     
  90.     
  91.     // Clean up.
  92.     if(timeunit == 0) timeunit = 1;
  93.     if(frametime == 0) frametime = 1;
  94.     if(beginpause == 0) slidebegin = NO;
  95.     if(endpause == 0) slideend = NO;
  96.     
  97.     return self;
  98. }
  99.  
  100. - initFrame:(NXRect *)frameRect
  101. {
  102.     [super initFrame:frameRect];
  103.     [self getDefaults];
  104.  
  105.     [self initMovie];
  106.     return self;
  107. }
  108.  
  109. - initMovie
  110. {
  111.     broken = NO;
  112.     running = NO;
  113.  
  114.     [self loadMovie];
  115.     if(!broken)
  116.     {
  117.         image = [imageList objectAt:0];
  118.         [image getSize:&imageRect.size];
  119.         [self setImageConstraints];
  120.     }
  121.     
  122.     state = msh_DARK;
  123.     currentFrame = 0;
  124.     wait = 1;
  125.     countdown = 1;
  126.  
  127.     slideDelta.x = randBetween(0.5, 4.0);
  128.     slideDelta.y = randBetween(0.5, 4.0);
  129.  
  130.     return self;
  131. }
  132.  
  133. - drawSelf:(const NXRect *)rects :(int)rectCount
  134. {
  135.     NXPoint p;
  136.  
  137.     if (!rects || !rectCount) return self;
  138.  
  139.     [super drawSelf:rects :rectCount];
  140.  
  141.     p.x = floor(imageRect.origin.x);
  142.     p.y = floor(imageRect.origin.y);
  143.     
  144.     // Draw current image.
  145.     if(broken) return self;
  146.     if(!running) [self cacheMovie];
  147.     [image composite:NX_SOVER toPoint:&p];
  148.  
  149.     return self;
  150. }
  151.  
  152. - oneStep
  153. {
  154.     int prevFrame;
  155.     
  156.     // Wait for designated time period.
  157.     if(![self timePassed:(wait*timeunit)]) return self;
  158.     if(!running) [self cacheMovie];
  159.     if(broken) return self;
  160.     
  161.     // Erase previous image.
  162.     prevFrame = currentFrame;
  163.     PSsetgray(0.0);
  164.     NXRectFill(&imageRect);
  165.  
  166.     // State machine.
  167.     if(--countdown == 0) 
  168.     {
  169.         // Determine new state and movie frame.
  170.         switch(state)
  171.     {
  172.     case msh_DARK:
  173.         if(beginpause != 0) { state = msh_BEGIN; currentFrame = 0; }
  174.         else { state = msh_FRAME; currentFrame = 0; }
  175.         break;
  176.     case msh_BEGIN:
  177.         state = msh_FRAME;
  178.         currentFrame = 0;
  179.         break;
  180.     case msh_FRAME:
  181.         if(currentFrame < (numberOfFrames-1))
  182.         { state = msh_FRAME; currentFrame++; }
  183.         else if(endpause != 0)
  184.         { state = msh_END; currentFrame = (numberOfFrames-1); }
  185.         else if(darktime != 0) { state = msh_DARK; currentFrame = 0; }
  186.         else if(beginpause != 0) { state = msh_BEGIN;  currentFrame = 0; }
  187.         else { state = msh_FRAME; currentFrame = 0; }
  188.         break;
  189.     case msh_END:
  190.         if(darktime != 0) { state = msh_DARK; currentFrame = 0; }
  191.         else if(beginpause != 0) { state = msh_BEGIN; currentFrame = 0; }
  192.         else { state = msh_FRAME; currentFrame = 0; }
  193.         break;
  194.     default:
  195.         state = msh_DARK; currentFrame = 0;
  196.         break;
  197.     }
  198.  
  199.     // Set waiting period and countdown repeater for new state.
  200.     switch(state)
  201.     {
  202.     case msh_DARK:
  203.         wait = darktime;
  204.         countdown = 1;
  205.         break;
  206.     case msh_BEGIN:
  207.         wait = (slidebegin ? 1 : beginpause);
  208.         countdown = (slidebegin ? beginpause : 1);
  209.         break;
  210.     case msh_FRAME:
  211.         wait = (slideframes ? 1 : frametime);
  212.         countdown = (slideframes ? frametime : 1);
  213.         break;
  214.     case msh_END:
  215.         wait = (slideend ? 1 : endpause);
  216.         countdown = (slideend ? endpause : 1);
  217.         break;
  218.     default:
  219.         wait = 1;
  220.         countdown = 1;
  221.         break;
  222.     }
  223.     }
  224.  
  225.     // Perform graphics action.
  226.     image = [imageList objectAt:currentFrame];
  227.     [image getSize:&imageRect.size];
  228.     [self setImageConstraints];
  229.     if(jump && currentFrame<prevFrame)
  230.     {
  231.     imageRect.origin.x = floor(randBetween(0, maxCoord.x));
  232.     imageRect.origin.y = floor(randBetween(0, maxCoord.y));
  233.     }
  234.     switch(state)
  235.     {
  236.     case msh_BEGIN:
  237.         if(slidebegin) [self slideImageRectOrigin];
  238.     [image composite:NX_SOVER toPoint:&imageRect.origin];
  239.     break;
  240.     case msh_FRAME:
  241.         if(slideframes) [self slideImageRectOrigin];
  242.     [image composite:NX_SOVER toPoint:&imageRect.origin];
  243.     break;
  244.     case msh_END:
  245.         if(slideend) [self slideImageRectOrigin];
  246.     [image composite:NX_SOVER toPoint:&imageRect.origin];
  247.     break;
  248.     }
  249.     return self;
  250. }
  251.  
  252. - slideImageRectOrigin
  253. {
  254.     float rand;
  255.     NXPoint p;
  256.  
  257.     p.x = imageRect.origin.x + slideDelta.x;
  258.     p.y = imageRect.origin.y + slideDelta.y;
  259.  
  260.     rand = randBetween(0.5, 4.0);
  261.  
  262.     if (p.x < 0) {
  263.         p.x = 0;
  264.         slideDelta.x = rand;
  265.     } else
  266.     if (p.x > maxCoord.x) {
  267.         p.x = maxCoord.x;
  268.         slideDelta.x = -rand;
  269.     }
  270.  
  271.     rand = randBetween(0.5, 4.0);
  272.  
  273.     if (p.y < 0) {
  274.         p.y = 0;
  275.         slideDelta.y = rand;
  276.     } else
  277.     if (p.y > maxCoord.y) {
  278.         p.y = maxCoord.y;
  279.         slideDelta.y = -rand;
  280.     }
  281.  
  282.     imageRect.origin.x = p.x;
  283.     imageRect.origin.y = p.y;
  284.  
  285.     return self;
  286. }
  287.  
  288. - loadMovie
  289. {
  290.     char filename[MAXPATHLEN];
  291.     char animFrame[MAXPATHLEN];
  292.     int i, len, fd;
  293.     id local_image;
  294.     const char *tiffext = ".tiff";
  295.     char animName[100];
  296.  
  297.  
  298.     // Reasonable directory name?
  299.     if(broken) return self;
  300.     if(!theMovie || !(theMovie[0]=='/' || theMovie[0]=='~'))
  301.     {
  302.     NXRunAlertPanel(module, "Bogus movie file.",
  303.         NULL, NULL, NULL, theMovie, module);
  304.         broken = TRUE;
  305.         return self;
  306.     }
  307.  
  308.     // Clean up directory name, replacing initial '~' with HOME.
  309.     if(theMovie[0] == '~')
  310.     {
  311.     strcpy(filename, NXHomeDirectory());
  312.     if(theMovie[1] != '/') strcat(filename, "/");
  313.     strcat(filename, theMovie+1);    
  314.     }
  315.     else strcpy(filename, theMovie);
  316.     len = strlen(filename);
  317.     if(len>1 && filename[len-1]=='/')
  318.         filename[--len] = 0;
  319.     
  320.  
  321.     imageList = [[List alloc] init];
  322.  
  323.     strcpy(animName,rindex(filename,'/')+1);
  324.     *rindex(animName,'.') = 0;
  325.  
  326.     for (i=0; ; i++)
  327.     {
  328.         sprintf(animFrame, "%s/%s.%d.tiff", filename, animName, i+1);
  329.         if (!(local_image = [NXImage findImageNamed:animFrame]))
  330.         {
  331.             if ((fd=open(animFrame, O_RDONLY)) < 0) break;
  332.             close(fd);
  333.  
  334.             local_image = [[NXImage alloc] initFromFile:animFrame];
  335.             if (local_image == NULL) break;    // never null, even if no file
  336.             [local_image setName:animFrame];
  337.         }
  338.  
  339.         [imageList addObject:local_image];
  340.     }
  341.     numberOfFrames = i;
  342.     currentFrame = 0;
  343.  
  344.     // Check if empty movie.
  345.     if((numberOfFrames = [imageList count]) <= 0)
  346.     {
  347.         NXRunAlertPanel(module, "Could not open any frames in movie folder \"%s\"\n\n",
  348.         NULL, NULL, NULL, filename);
  349.         broken = TRUE;
  350.         return self;
  351.     }
  352.  
  353.     return self;
  354. }
  355.  
  356. - cacheMovie
  357. {
  358.     id this_image;
  359.     int i;
  360.  
  361.     // Force lazy images to load now so that first movie run is correct speed.
  362.     if(running) return self;
  363.     running = YES;
  364.  
  365.     numberOfFrames = [imageList count];
  366.     for(i=0; i<numberOfFrames; i++)
  367.     {
  368.         this_image = [imageList objectAt:i];
  369.     if([this_image lockFocus]) [this_image unlockFocus];
  370.     else fprintf(stderr, "%s: bad image: %s\n",
  371.         module, [this_image name]);
  372.     }
  373.     return self;
  374. }
  375.  
  376. // override this method so that Thinker can't set the default image.
  377. - setImage:newImage
  378. {
  379.     return self;
  380. }
  381.  
  382. // override
  383. - (BOOL) useBufferedWindow
  384. {
  385.     return YES;
  386. }
  387.  
  388.  
  389.  
  390. - setJump:sender
  391. {
  392.     jump = [jumpButton state] ? YES:NO;
  393.     NXWriteDefault("MovieShow", "Jump", jump ? "YES":"NO");
  394.     return self;
  395. }
  396.  
  397. - setSlideFrames:sender
  398. {
  399.     slideframes = [slideFramesButton state] ? YES:NO;
  400.     NXWriteDefault("MovieShow", "SlideFrames", slideframes ? "YES":"NO");
  401.     return self;
  402. }
  403.  
  404. - setSlidePauses:sender
  405. {
  406.     slidebegin = slideend = [slidePausesButton state] ? YES:NO;
  407.     NXWriteDefault("MovieShow", "SlidePauses", slidebegin ? "YES":"NO");
  408.     return self;
  409. }
  410.  
  411. - setFile:sender
  412. {
  413.     const char *const types[] = {"tiff", NULL};  
  414.     char *iptr;
  415.     BOOL done = NO;
  416.     int i;
  417.  
  418. //    if ([[OpenPanel new] runModalForTypes:types])
  419.     do {
  420.         if ([[OpenPanel new] runModalForDirectory:theMovie file:"" types:types])
  421.         {
  422.             if (movieNameBuffer) free(movieNameBuffer);
  423.             theMovie = movieNameBuffer = NXCopyStringBuffer([[OpenPanel new] filename]);
  424.  
  425.             if (iptr = rindex(movieNameBuffer, '/')) *iptr = '\0';
  426.             i = strlen(movieNameBuffer);
  427.  
  428.             if (i > 5 && !strcmp(&movieNameBuffer[i-5], ".anim"))
  429.             {
  430.                 [filesTextField setStringValue:theMovie];
  431.  
  432.                 NXWriteDefault("MovieShow", "Movie", theMovie);
  433.  
  434.                 [imageList freeObjects];
  435.                 [imageList free];
  436.                 imageList = nil;
  437.  
  438.                 [self initMovie];
  439.                 done = YES;
  440.             }
  441.             else
  442.             {
  443.                 NXRunAlertPanel(module, 
  444.                     "Please select a tiff in a \".anim\" folder.", NULL, NULL, NULL);
  445.             }
  446.         }
  447.         else done = YES;
  448.  
  449.     } while (!done);
  450.  
  451.     return self;
  452. }
  453.  
  454. - setBeginPause:sender
  455. {
  456.     char str[100];
  457.     beginpause = [beginPauseTextField intValue];
  458.     sprintf(str,"%d", (int)beginpause);
  459.     NXWriteDefault("MovieShow", "BeginPause", str);
  460.     return self;
  461. }
  462.  
  463. - setEndPause:sender
  464. {
  465.     char str[100];
  466.     endpause = [endPauseTextField intValue];
  467.     sprintf(str,"%d", (int)endpause);
  468.     NXWriteDefault("MovieShow", "EndPause", str);
  469.     return self;
  470. }
  471.  
  472. - setDarkFor:sender
  473. {
  474.     char str[100];
  475.     darktime = [darkForTextField intValue];
  476.     sprintf(str,"%d", (int)darktime);
  477.     NXWriteDefault("MovieShow", "DarkTime", str);
  478.     return self;
  479. }
  480.  
  481. - setTimeUnit:sender
  482. {
  483.     char str[100];
  484.     timeunit = [timeUnitTextField intValue];
  485.     sprintf(str,"%d", (int)timeunit);
  486.     NXWriteDefault("MovieShow", "TimeUnit", str);
  487.     return self;
  488. }
  489.  
  490. - inspector:sender
  491. {
  492.     char buf[MAXPATHLEN];
  493.     
  494.     if (!inspectorPanel)
  495.     {
  496.         sprintf(buf,"%s/movie.nib",[sender moduleDirectory:"MovieShow"]);
  497.         [NXApp loadNibFile:buf owner:self withNames:NO];
  498.  
  499.         [filesTextField setStringValue:theMovie];
  500.  
  501.         [beginPauseTextField setIntValue:beginpause];
  502.         [endPauseTextField setIntValue:endpause];
  503.         [darkForTextField setIntValue:darktime];
  504.         [timeUnitTextField setIntValue:timeunit];
  505.  
  506.         [jumpButton setState: (jump ? 1:0)];
  507.         [slideFramesButton setState: (slideframes ? 1:0)];
  508.         [slidePausesButton setState: (slidebegin ? 1:0)];
  509.     }
  510.     return inspectorPanel;
  511. }
  512.  
  513.  
  514. @end
  515.